/**
 * @licstart The following is the entire license notice for the
 * Javascript code in this page
 *
 * Copyright 2021 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @licend The above is the entire license notice for the
 * Javascript code in this page
 */
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.calculateSHA384 = calculateSHA384;
exports.PDF20 = exports.PDF17 = exports.CipherTransformFactory = exports.calculateSHA512 = exports.calculateSHA256 = exports.calculateMD5 = exports.ARCFourCipher = exports.AES256Cipher = exports.AES128Cipher = void 0;

var _util = require("../shared/util.js");

var _primitives = require("./primitives.js");

var _stream = require("./stream.js");

class ARCFourCipher {
  constructor(key) {
    this.a = 0;
    this.b = 0;
    var s = new Uint8Array(256);
    var i,
        j = 0,
        tmp,
        keyLength = key.length;

    for (i = 0; i < 256; ++i) {
      s[i] = i;
    }

    for (i = 0; i < 256; ++i) {
      tmp = s[i];
      j = j + tmp + key[i % keyLength] & 0xff;
      s[i] = s[j];
      s[j] = tmp;
    }

    this.s = s;
  }

  encryptBlock(data) {
    var i,
        n = data.length,
        tmp,
        tmp2;
    var a = this.a,
        b = this.b,
        s = this.s;
    var output = new Uint8Array(n);

    for (i = 0; i < n; ++i) {
      a = a + 1 & 0xff;
      tmp = s[a];
      b = b + tmp & 0xff;
      tmp2 = s[b];
      s[a] = tmp2;
      s[b] = tmp;
      output[i] = data[i] ^ s[tmp + tmp2 & 0xff];
    }

    this.a = a;
    this.b = b;
    return output;
  }

  decryptBlock(data) {
    return this.encryptBlock(data);
  }

  encrypt(data) {
    return this.encryptBlock(data);
  }

}

exports.ARCFourCipher = ARCFourCipher;

var calculateMD5 = function calculateMD5Closure() {
  var r = new Uint8Array([7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
  var k = new Int32Array([-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556, -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222, -722521979, 76029189, -640364487, -421815835, 530742520, -995338651, -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379, 718787259, -343485551]);

  function hash(data, offset, length) {
    var h0 = 1732584193,
        h1 = -271733879,
        h2 = -1732584194,
        h3 = 271733878;
    var paddedLength = length + 72 & ~63;
    var padded = new Uint8Array(paddedLength);
    var i, j, n;

    for (i = 0; i < length; ++i) {
      padded[i] = data[offset++];
    }

    padded[i++] = 0x80;
    n = paddedLength - 8;

    while (i < n) {
      padded[i++] = 0;
    }

    padded[i++] = length << 3 & 0xff;
    padded[i++] = length >> 5 & 0xff;
    padded[i++] = length >> 13 & 0xff;
    padded[i++] = length >> 21 & 0xff;
    padded[i++] = length >>> 29 & 0xff;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    var w = new Int32Array(16);

    for (i = 0; i < paddedLength;) {
      for (j = 0; j < 16; ++j, i += 4) {
        w[j] = padded[i] | padded[i + 1] << 8 | padded[i + 2] << 16 | padded[i + 3] << 24;
      }

      var a = h0,
          b = h1,
          c = h2,
          d = h3,
          f,
          g;

      for (j = 0; j < 64; ++j) {
        if (j < 16) {
          f = b & c | ~b & d;
          g = j;
        } else if (j < 32) {
          f = d & b | ~d & c;
          g = 5 * j + 1 & 15;
        } else if (j < 48) {
          f = b ^ c ^ d;
          g = 3 * j + 5 & 15;
        } else {
          f = c ^ (b | ~d);
          g = 7 * j & 15;
        }

        var tmp = d,
            rotateArg = a + f + k[j] + w[g] | 0,
            rotate = r[j];
        d = c;
        c = b;
        b = b + (rotateArg << rotate | rotateArg >>> 32 - rotate) | 0;
        a = tmp;
      }

      h0 = h0 + a | 0;
      h1 = h1 + b | 0;
      h2 = h2 + c | 0;
      h3 = h3 + d | 0;
    }

    return new Uint8Array([h0 & 0xFF, h0 >> 8 & 0xFF, h0 >> 16 & 0xFF, h0 >>> 24 & 0xFF, h1 & 0xFF, h1 >> 8 & 0xFF, h1 >> 16 & 0xFF, h1 >>> 24 & 0xFF, h2 & 0xFF, h2 >> 8 & 0xFF, h2 >> 16 & 0xFF, h2 >>> 24 & 0xFF, h3 & 0xFF, h3 >> 8 & 0xFF, h3 >> 16 & 0xFF, h3 >>> 24 & 0xFF]);
  }

  return hash;
}();

exports.calculateMD5 = calculateMD5;

class Word64 {
  constructor(highInteger, lowInteger) {
    this.high = highInteger | 0;
    this.low = lowInteger | 0;
  }

  and(word) {
    this.high &= word.high;
    this.low &= word.low;
  }

  xor(word) {
    this.high ^= word.high;
    this.low ^= word.low;
  }

  or(word) {
    this.high |= word.high;
    this.low |= word.low;
  }

  shiftRight(places) {
    if (places >= 32) {
      this.low = this.high >>> places - 32 | 0;
      this.high = 0;
    } else {
      this.low = this.low >>> places | this.high << 32 - places;
      this.high = this.high >>> places | 0;
    }
  }

  shiftLeft(places) {
    if (places >= 32) {
      this.high = this.low << places - 32;
      this.low = 0;
    } else {
      this.high = this.high << places | this.low >>> 32 - places;
      this.low = this.low << places;
    }
  }

  rotateRight(places) {
    var low, high;

    if (places & 32) {
      high = this.low;
      low = this.high;
    } else {
      low = this.low;
      high = this.high;
    }

    places &= 31;
    this.low = low >>> places | high << 32 - places;
    this.high = high >>> places | low << 32 - places;
  }

  not() {
    this.high = ~this.high;
    this.low = ~this.low;
  }

  add(word) {
    var lowAdd = (this.low >>> 0) + (word.low >>> 0);
    var highAdd = (this.high >>> 0) + (word.high >>> 0);

    if (lowAdd > 0xffffffff) {
      highAdd += 1;
    }

    this.low = lowAdd | 0;
    this.high = highAdd | 0;
  }

  copyTo(bytes, offset) {
    bytes[offset] = this.high >>> 24 & 0xff;
    bytes[offset + 1] = this.high >> 16 & 0xff;
    bytes[offset + 2] = this.high >> 8 & 0xff;
    bytes[offset + 3] = this.high & 0xff;
    bytes[offset + 4] = this.low >>> 24 & 0xff;
    bytes[offset + 5] = this.low >> 16 & 0xff;
    bytes[offset + 6] = this.low >> 8 & 0xff;
    bytes[offset + 7] = this.low & 0xff;
  }

  assign(word) {
    this.high = word.high;
    this.low = word.low;
  }

}

var calculateSHA256 = function calculateSHA256Closure() {
  function rotr(x, n) {
    return x >>> n | x << 32 - n;
  }

  function ch(x, y, z) {
    return x & y ^ ~x & z;
  }

  function maj(x, y, z) {
    return x & y ^ x & z ^ y & z;
  }

  function sigma(x) {
    return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
  }

  function sigmaPrime(x) {
    return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
  }

  function littleSigma(x) {
    return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3;
  }

  function littleSigmaPrime(x) {
    return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10;
  }

  var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];

  function hash(data, offset, length) {
    var h0 = 0x6a09e667,
        h1 = 0xbb67ae85,
        h2 = 0x3c6ef372,
        h3 = 0xa54ff53a,
        h4 = 0x510e527f,
        h5 = 0x9b05688c,
        h6 = 0x1f83d9ab,
        h7 = 0x5be0cd19;
    var paddedLength = Math.ceil((length + 9) / 64) * 64;
    var padded = new Uint8Array(paddedLength);
    var i, j, n;

    for (i = 0; i < length; ++i) {
      padded[i] = data[offset++];
    }

    padded[i++] = 0x80;
    n = paddedLength - 8;

    while (i < n) {
      padded[i++] = 0;
    }

    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = length >>> 29 & 0xff;
    padded[i++] = length >> 21 & 0xff;
    padded[i++] = length >> 13 & 0xff;
    padded[i++] = length >> 5 & 0xff;
    padded[i++] = length << 3 & 0xff;
    var w = new Uint32Array(64);

    for (i = 0; i < paddedLength;) {
      for (j = 0; j < 16; ++j) {
        w[j] = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3];
        i += 4;
      }

      for (j = 16; j < 64; ++j) {
        w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] + littleSigma(w[j - 15]) + w[j - 16] | 0;
      }

      var a = h0,
          b = h1,
          c = h2,
          d = h3,
          e = h4,
          f = h5,
          g = h6,
          h = h7,
          t1,
          t2;

      for (j = 0; j < 64; ++j) {
        t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j];
        t2 = sigma(a) + maj(a, b, c);
        h = g;
        g = f;
        f = e;
        e = d + t1 | 0;
        d = c;
        c = b;
        b = a;
        a = t1 + t2 | 0;
      }

      h0 = h0 + a | 0;
      h1 = h1 + b | 0;
      h2 = h2 + c | 0;
      h3 = h3 + d | 0;
      h4 = h4 + e | 0;
      h5 = h5 + f | 0;
      h6 = h6 + g | 0;
      h7 = h7 + h | 0;
    }

    return new Uint8Array([h0 >> 24 & 0xFF, h0 >> 16 & 0xFF, h0 >> 8 & 0xFF, h0 & 0xFF, h1 >> 24 & 0xFF, h1 >> 16 & 0xFF, h1 >> 8 & 0xFF, h1 & 0xFF, h2 >> 24 & 0xFF, h2 >> 16 & 0xFF, h2 >> 8 & 0xFF, h2 & 0xFF, h3 >> 24 & 0xFF, h3 >> 16 & 0xFF, h3 >> 8 & 0xFF, h3 & 0xFF, h4 >> 24 & 0xFF, h4 >> 16 & 0xFF, h4 >> 8 & 0xFF, h4 & 0xFF, h5 >> 24 & 0xFF, h5 >> 16 & 0xFF, h5 >> 8 & 0xFF, h5 & 0xFF, h6 >> 24 & 0xFF, h6 >> 16 & 0xFF, h6 >> 8 & 0xFF, h6 & 0xFF, h7 >> 24 & 0xFF, h7 >> 16 & 0xFF, h7 >> 8 & 0xFF, h7 & 0xFF]);
  }

  return hash;
}();

exports.calculateSHA256 = calculateSHA256;

var calculateSHA512 = function calculateSHA512Closure() {
  function ch(result, x, y, z, tmp) {
    result.assign(x);
    result.and(y);
    tmp.assign(x);
    tmp.not();
    tmp.and(z);
    result.xor(tmp);
  }

  function maj(result, x, y, z, tmp) {
    result.assign(x);
    result.and(y);
    tmp.assign(x);
    tmp.and(z);
    result.xor(tmp);
    tmp.assign(y);
    tmp.and(z);
    result.xor(tmp);
  }

  function sigma(result, x, tmp) {
    result.assign(x);
    result.rotateRight(28);
    tmp.assign(x);
    tmp.rotateRight(34);
    result.xor(tmp);
    tmp.assign(x);
    tmp.rotateRight(39);
    result.xor(tmp);
  }

  function sigmaPrime(result, x, tmp) {
    result.assign(x);
    result.rotateRight(14);
    tmp.assign(x);
    tmp.rotateRight(18);
    result.xor(tmp);
    tmp.assign(x);
    tmp.rotateRight(41);
    result.xor(tmp);
  }

  function littleSigma(result, x, tmp) {
    result.assign(x);
    result.rotateRight(1);
    tmp.assign(x);
    tmp.rotateRight(8);
    result.xor(tmp);
    tmp.assign(x);
    tmp.shiftRight(7);
    result.xor(tmp);
  }

  function littleSigmaPrime(result, x, tmp) {
    result.assign(x);
    result.rotateRight(19);
    tmp.assign(x);
    tmp.rotateRight(61);
    result.xor(tmp);
    tmp.assign(x);
    tmp.shiftRight(6);
    result.xor(tmp);
  }

  var k = [new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd), new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc), new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019), new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118), new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe), new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2), new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1), new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694), new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3), new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65), new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483), new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5), new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210), new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4), new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725), new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70), new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926), new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df), new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8), new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b), new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001), new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30), new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910), new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8), new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53), new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8), new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb), new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3), new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60), new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec), new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9), new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b), new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207), new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178), new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6), new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b), new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493), new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c), new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a), new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)];

  function hash(data, offset, length, mode384 = false) {
    var h0, h1, h2, h3, h4, h5, h6, h7;

    if (!mode384) {
      h0 = new Word64(0x6a09e667, 0xf3bcc908);
      h1 = new Word64(0xbb67ae85, 0x84caa73b);
      h2 = new Word64(0x3c6ef372, 0xfe94f82b);
      h3 = new Word64(0xa54ff53a, 0x5f1d36f1);
      h4 = new Word64(0x510e527f, 0xade682d1);
      h5 = new Word64(0x9b05688c, 0x2b3e6c1f);
      h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);
      h7 = new Word64(0x5be0cd19, 0x137e2179);
    } else {
      h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
      h1 = new Word64(0x629a292a, 0x367cd507);
      h2 = new Word64(0x9159015a, 0x3070dd17);
      h3 = new Word64(0x152fecd8, 0xf70e5939);
      h4 = new Word64(0x67332667, 0xffc00b31);
      h5 = new Word64(0x8eb44a87, 0x68581511);
      h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);
      h7 = new Word64(0x47b5481d, 0xbefa4fa4);
    }

    var paddedLength = Math.ceil((length + 17) / 128) * 128;
    var padded = new Uint8Array(paddedLength);
    var i, j, n;

    for (i = 0; i < length; ++i) {
      padded[i] = data[offset++];
    }

    padded[i++] = 0x80;
    n = paddedLength - 16;

    while (i < n) {
      padded[i++] = 0;
    }

    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = 0;
    padded[i++] = length >>> 29 & 0xff;
    padded[i++] = length >> 21 & 0xff;
    padded[i++] = length >> 13 & 0xff;
    padded[i++] = length >> 5 & 0xff;
    padded[i++] = length << 3 & 0xff;
    var w = new Array(80);

    for (i = 0; i < 80; i++) {
      w[i] = new Word64(0, 0);
    }

    var a = new Word64(0, 0),
        b = new Word64(0, 0),
        c = new Word64(0, 0);
    var d = new Word64(0, 0),
        e = new Word64(0, 0),
        f = new Word64(0, 0);
    var g = new Word64(0, 0),
        h = new Word64(0, 0);
    var t1 = new Word64(0, 0),
        t2 = new Word64(0, 0);
    var tmp1 = new Word64(0, 0),
        tmp2 = new Word64(0, 0),
        tmp3;

    for (i = 0; i < paddedLength;) {
      for (j = 0; j < 16; ++j) {
        w[j].high = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3];
        w[j].low = padded[i + 4] << 24 | padded[i + 5] << 16 | padded[i + 6] << 8 | padded[i + 7];
        i += 8;
      }

      for (j = 16; j < 80; ++j) {
        tmp3 = w[j];
        littleSigmaPrime(tmp3, w[j - 2], tmp2);
        tmp3.add(w[j - 7]);
        littleSigma(tmp1, w[j - 15], tmp2);
        tmp3.add(tmp1);
        tmp3.add(w[j - 16]);
      }

      a.assign(h0);
      b.assign(h1);
      c.assign(h2);
      d.assign(h3);
      e.assign(h4);
      f.assign(h5);
      g.assign(h6);
      h.assign(h7);

      for (j = 0; j < 80; ++j) {
        t1.assign(h);
        sigmaPrime(tmp1, e, tmp2);
        t1.add(tmp1);
        ch(tmp1, e, f, g, tmp2);
        t1.add(tmp1);
        t1.add(k[j]);
        t1.add(w[j]);
        sigma(t2, a, tmp2);
        maj(tmp1, a, b, c, tmp2);
        t2.add(tmp1);
        tmp3 = h;
        h = g;
        g = f;
        f = e;
        d.add(t1);
        e = d;
        d = c;
        c = b;
        b = a;
        tmp3.assign(t1);
        tmp3.add(t2);
        a = tmp3;
      }

      h0.add(a);
      h1.add(b);
      h2.add(c);
      h3.add(d);
      h4.add(e);
      h5.add(f);
      h6.add(g);
      h7.add(h);
    }

    var result;

    if (!mode384) {
      result = new Uint8Array(64);
      h0.copyTo(result, 0);
      h1.copyTo(result, 8);
      h2.copyTo(result, 16);
      h3.copyTo(result, 24);
      h4.copyTo(result, 32);
      h5.copyTo(result, 40);
      h6.copyTo(result, 48);
      h7.copyTo(result, 56);
    } else {
      result = new Uint8Array(48);
      h0.copyTo(result, 0);
      h1.copyTo(result, 8);
      h2.copyTo(result, 16);
      h3.copyTo(result, 24);
      h4.copyTo(result, 32);
      h5.copyTo(result, 40);
    }

    return result;
  }

  return hash;
}();

exports.calculateSHA512 = calculateSHA512;

function calculateSHA384(data, offset, length) {
  return calculateSHA512(data, offset, length, true);
}

class NullCipher {
  decryptBlock(data) {
    return data;
  }

  encrypt(data) {
    return data;
  }

}

class AESBaseCipher {
  constructor() {
    if (this.constructor === AESBaseCipher) {
      (0, _util.unreachable)("Cannot initialize AESBaseCipher.");
    }

    this._s = new Uint8Array([0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]);
    this._inv_s = new Uint8Array([0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]);
    this._mix = new Uint32Array([0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
    this._mixCol = new Uint8Array(256);

    for (let i = 0; i < 256; i++) {
      if (i < 128) {
        this._mixCol[i] = i << 1;
      } else {
        this._mixCol[i] = i << 1 ^ 0x1b;
      }
    }

    this.buffer = new Uint8Array(16);
    this.bufferPosition = 0;
  }

  _expandKey(cipherKey) {
    (0, _util.unreachable)("Cannot call `_expandKey` on the base class");
  }

  _decrypt(input, key) {
    let t, u, v;
    const state = new Uint8Array(16);
    state.set(input);

    for (let j = 0, k = this._keySize; j < 16; ++j, ++k) {
      state[j] ^= key[k];
    }

    for (let i = this._cyclesOfRepetition - 1; i >= 1; --i) {
      t = state[13];
      state[13] = state[9];
      state[9] = state[5];
      state[5] = state[1];
      state[1] = t;
      t = state[14];
      u = state[10];
      state[14] = state[6];
      state[10] = state[2];
      state[6] = t;
      state[2] = u;
      t = state[15];
      u = state[11];
      v = state[7];
      state[15] = state[3];
      state[11] = t;
      state[7] = u;
      state[3] = v;

      for (let j = 0; j < 16; ++j) {
        state[j] = this._inv_s[state[j]];
      }

      for (let j = 0, k = i * 16; j < 16; ++j, ++k) {
        state[j] ^= key[k];
      }

      for (let j = 0; j < 16; j += 4) {
        const s0 = this._mix[state[j]];
        const s1 = this._mix[state[j + 1]];
        const s2 = this._mix[state[j + 2]];
        const s3 = this._mix[state[j + 3]];
        t = s0 ^ s1 >>> 8 ^ s1 << 24 ^ s2 >>> 16 ^ s2 << 16 ^ s3 >>> 24 ^ s3 << 8;
        state[j] = t >>> 24 & 0xff;
        state[j + 1] = t >> 16 & 0xff;
        state[j + 2] = t >> 8 & 0xff;
        state[j + 3] = t & 0xff;
      }
    }

    t = state[13];
    state[13] = state[9];
    state[9] = state[5];
    state[5] = state[1];
    state[1] = t;
    t = state[14];
    u = state[10];
    state[14] = state[6];
    state[10] = state[2];
    state[6] = t;
    state[2] = u;
    t = state[15];
    u = state[11];
    v = state[7];
    state[15] = state[3];
    state[11] = t;
    state[7] = u;
    state[3] = v;

    for (let j = 0; j < 16; ++j) {
      state[j] = this._inv_s[state[j]];
      state[j] ^= key[j];
    }

    return state;
  }

  _encrypt(input, key) {
    const s = this._s;
    let t, u, v;
    const state = new Uint8Array(16);
    state.set(input);

    for (let j = 0; j < 16; ++j) {
      state[j] ^= key[j];
    }

    for (let i = 1; i < this._cyclesOfRepetition; i++) {
      for (let j = 0; j < 16; ++j) {
        state[j] = s[state[j]];
      }

      v = state[1];
      state[1] = state[5];
      state[5] = state[9];
      state[9] = state[13];
      state[13] = v;
      v = state[2];
      u = state[6];
      state[2] = state[10];
      state[6] = state[14];
      state[10] = v;
      state[14] = u;
      v = state[3];
      u = state[7];
      t = state[11];
      state[3] = state[15];
      state[7] = v;
      state[11] = u;
      state[15] = t;

      for (let j = 0; j < 16; j += 4) {
        const s0 = state[j + 0];
        const s1 = state[j + 1];
        const s2 = state[j + 2];
        const s3 = state[j + 3];
        t = s0 ^ s1 ^ s2 ^ s3;
        state[j + 0] ^= t ^ this._mixCol[s0 ^ s1];
        state[j + 1] ^= t ^ this._mixCol[s1 ^ s2];
        state[j + 2] ^= t ^ this._mixCol[s2 ^ s3];
        state[j + 3] ^= t ^ this._mixCol[s3 ^ s0];
      }

      for (let j = 0, k = i * 16; j < 16; ++j, ++k) {
        state[j] ^= key[k];
      }
    }

    for (let j = 0; j < 16; ++j) {
      state[j] = s[state[j]];
    }

    v = state[1];
    state[1] = state[5];
    state[5] = state[9];
    state[9] = state[13];
    state[13] = v;
    v = state[2];
    u = state[6];
    state[2] = state[10];
    state[6] = state[14];
    state[10] = v;
    state[14] = u;
    v = state[3];
    u = state[7];
    t = state[11];
    state[3] = state[15];
    state[7] = v;
    state[11] = u;
    state[15] = t;

    for (let j = 0, k = this._keySize; j < 16; ++j, ++k) {
      state[j] ^= key[k];
    }

    return state;
  }

  _decryptBlock2(data, finalize) {
    const sourceLength = data.length;
    let buffer = this.buffer,
        bufferLength = this.bufferPosition;
    const result = [];
    let iv = this.iv;

    for (let i = 0; i < sourceLength; ++i) {
      buffer[bufferLength] = data[i];
      ++bufferLength;

      if (bufferLength < 16) {
        continue;
      }

      const plain = this._decrypt(buffer, this._key);

      for (let j = 0; j < 16; ++j) {
        plain[j] ^= iv[j];
      }

      iv = buffer;
      result.push(plain);
      buffer = new Uint8Array(16);
      bufferLength = 0;
    }

    this.buffer = buffer;
    this.bufferLength = bufferLength;
    this.iv = iv;

    if (result.length === 0) {
      return new Uint8Array(0);
    }

    let outputLength = 16 * result.length;

    if (finalize) {
      const lastBlock = result[result.length - 1];
      let psLen = lastBlock[15];

      if (psLen <= 16) {
        for (let i = 15, ii = 16 - psLen; i >= ii; --i) {
          if (lastBlock[i] !== psLen) {
            psLen = 0;
            break;
          }
        }

        outputLength -= psLen;
        result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
      }
    }

    const output = new Uint8Array(outputLength);

    for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
      output.set(result[i], j);
    }

    return output;
  }

  decryptBlock(data, finalize, iv = null) {
    const sourceLength = data.length;
    const buffer = this.buffer;
    let bufferLength = this.bufferPosition;

    if (iv) {
      this.iv = iv;
    } else {
      for (let i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {
        buffer[bufferLength] = data[i];
      }

      if (bufferLength < 16) {
        this.bufferLength = bufferLength;
        return new Uint8Array(0);
      }

      this.iv = buffer;
      data = data.subarray(16);
    }

    this.buffer = new Uint8Array(16);
    this.bufferLength = 0;
    this.decryptBlock = this._decryptBlock2;
    return this.decryptBlock(data, finalize);
  }

  encrypt(data, iv) {
    const sourceLength = data.length;
    let buffer = this.buffer,
        bufferLength = this.bufferPosition;
    const result = [];

    if (!iv) {
      iv = new Uint8Array(16);
    }

    for (let i = 0; i < sourceLength; ++i) {
      buffer[bufferLength] = data[i];
      ++bufferLength;

      if (bufferLength < 16) {
        continue;
      }

      for (let j = 0; j < 16; ++j) {
        buffer[j] ^= iv[j];
      }

      const cipher = this._encrypt(buffer, this._key);

      iv = cipher;
      result.push(cipher);
      buffer = new Uint8Array(16);
      bufferLength = 0;
    }

    this.buffer = buffer;
    this.bufferLength = bufferLength;
    this.iv = iv;

    if (result.length === 0) {
      return new Uint8Array(0);
    }

    const outputLength = 16 * result.length;
    const output = new Uint8Array(outputLength);

    for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
      output.set(result[i], j);
    }

    return output;
  }

}

class AES128Cipher extends AESBaseCipher {
  constructor(key) {
    super();
    this._cyclesOfRepetition = 10;
    this._keySize = 160;
    this._rcon = new Uint8Array([0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d]);
    this._key = this._expandKey(key);
  }

  _expandKey(cipherKey) {
    const b = 176;
    const s = this._s;
    const rcon = this._rcon;
    const result = new Uint8Array(b);
    result.set(cipherKey);

    for (let j = 16, i = 1; j < b; ++i) {
      let t1 = result[j - 3];
      let t2 = result[j - 2];
      let t3 = result[j - 1];
      let t4 = result[j - 4];
      t1 = s[t1];
      t2 = s[t2];
      t3 = s[t3];
      t4 = s[t4];
      t1 = t1 ^ rcon[i];

      for (let n = 0; n < 4; ++n) {
        result[j] = t1 ^= result[j - 16];
        j++;
        result[j] = t2 ^= result[j - 16];
        j++;
        result[j] = t3 ^= result[j - 16];
        j++;
        result[j] = t4 ^= result[j - 16];
        j++;
      }
    }

    return result;
  }

}

exports.AES128Cipher = AES128Cipher;

class AES256Cipher extends AESBaseCipher {
  constructor(key) {
    super();
    this._cyclesOfRepetition = 14;
    this._keySize = 224;
    this._key = this._expandKey(key);
  }

  _expandKey(cipherKey) {
    const b = 240;
    const s = this._s;
    const result = new Uint8Array(b);
    result.set(cipherKey);
    let r = 1;
    let t1, t2, t3, t4;

    for (let j = 32, i = 1; j < b; ++i) {
      if (j % 32 === 16) {
        t1 = s[t1];
        t2 = s[t2];
        t3 = s[t3];
        t4 = s[t4];
      } else if (j % 32 === 0) {
        t1 = result[j - 3];
        t2 = result[j - 2];
        t3 = result[j - 1];
        t4 = result[j - 4];
        t1 = s[t1];
        t2 = s[t2];
        t3 = s[t3];
        t4 = s[t4];
        t1 = t1 ^ r;

        if ((r <<= 1) >= 256) {
          r = (r ^ 0x1b) & 0xff;
        }
      }

      for (let n = 0; n < 4; ++n) {
        result[j] = t1 ^= result[j - 32];
        j++;
        result[j] = t2 ^= result[j - 32];
        j++;
        result[j] = t3 ^= result[j - 32];
        j++;
        result[j] = t4 ^= result[j - 32];
        j++;
      }
    }

    return result;
  }

}

exports.AES256Cipher = AES256Cipher;

class PDF17 {
  checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) {
    var hashData = new Uint8Array(password.length + 56);
    hashData.set(password, 0);
    hashData.set(ownerValidationSalt, password.length);
    hashData.set(userBytes, password.length + ownerValidationSalt.length);
    var result = calculateSHA256(hashData, 0, hashData.length);
    return (0, _util.isArrayEqual)(result, ownerPassword);
  }

  checkUserPassword(password, userValidationSalt, userPassword) {
    var hashData = new Uint8Array(password.length + 8);
    hashData.set(password, 0);
    hashData.set(userValidationSalt, password.length);
    var result = calculateSHA256(hashData, 0, hashData.length);
    return (0, _util.isArrayEqual)(result, userPassword);
  }

  getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) {
    var hashData = new Uint8Array(password.length + 56);
    hashData.set(password, 0);
    hashData.set(ownerKeySalt, password.length);
    hashData.set(userBytes, password.length + ownerKeySalt.length);
    var key = calculateSHA256(hashData, 0, hashData.length);
    var cipher = new AES256Cipher(key);
    return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16));
  }

  getUserKey(password, userKeySalt, userEncryption) {
    var hashData = new Uint8Array(password.length + 8);
    hashData.set(password, 0);
    hashData.set(userKeySalt, password.length);
    var key = calculateSHA256(hashData, 0, hashData.length);
    var cipher = new AES256Cipher(key);
    return cipher.decryptBlock(userEncryption, false, new Uint8Array(16));
  }

}

exports.PDF17 = PDF17;

var PDF20 = function PDF20Closure() {
  function calculatePDF20Hash(password, input, userBytes) {
    var k = calculateSHA256(input, 0, input.length).subarray(0, 32);
    var e = [0];
    var i = 0;

    while (i < 64 || e[e.length - 1] > i - 32) {
      const combinedLength = password.length + k.length + userBytes.length,
            combinedArray = new Uint8Array(combinedLength);
      let writeOffset = 0;
      combinedArray.set(password, writeOffset);
      writeOffset += password.length;
      combinedArray.set(k, writeOffset);
      writeOffset += k.length;
      combinedArray.set(userBytes, writeOffset);
      var k1 = new Uint8Array(combinedLength * 64);

      for (var j = 0, pos = 0; j < 64; j++, pos += combinedLength) {
        k1.set(combinedArray, pos);
      }

      var cipher = new AES128Cipher(k.subarray(0, 16));
      e = cipher.encrypt(k1, k.subarray(16, 32));
      var remainder = 0;

      for (var z = 0; z < 16; z++) {
        remainder *= 256 % 3;
        remainder %= 3;
        remainder += (e[z] >>> 0) % 3;
        remainder %= 3;
      }

      if (remainder === 0) {
        k = calculateSHA256(e, 0, e.length);
      } else if (remainder === 1) {
        k = calculateSHA384(e, 0, e.length);
      } else if (remainder === 2) {
        k = calculateSHA512(e, 0, e.length);
      }

      i++;
    }

    return k.subarray(0, 32);
  }

  class PDF20 {
    hash(password, concatBytes, userBytes) {
      return calculatePDF20Hash(password, concatBytes, userBytes);
    }

    checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) {
      var hashData = new Uint8Array(password.length + 56);
      hashData.set(password, 0);
      hashData.set(ownerValidationSalt, password.length);
      hashData.set(userBytes, password.length + ownerValidationSalt.length);
      var result = calculatePDF20Hash(password, hashData, userBytes);
      return (0, _util.isArrayEqual)(result, ownerPassword);
    }

    checkUserPassword(password, userValidationSalt, userPassword) {
      var hashData = new Uint8Array(password.length + 8);
      hashData.set(password, 0);
      hashData.set(userValidationSalt, password.length);
      var result = calculatePDF20Hash(password, hashData, []);
      return (0, _util.isArrayEqual)(result, userPassword);
    }

    getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) {
      var hashData = new Uint8Array(password.length + 56);
      hashData.set(password, 0);
      hashData.set(ownerKeySalt, password.length);
      hashData.set(userBytes, password.length + ownerKeySalt.length);
      var key = calculatePDF20Hash(password, hashData, userBytes);
      var cipher = new AES256Cipher(key);
      return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16));
    }

    getUserKey(password, userKeySalt, userEncryption) {
      var hashData = new Uint8Array(password.length + 8);
      hashData.set(password, 0);
      hashData.set(userKeySalt, password.length);
      var key = calculatePDF20Hash(password, hashData, []);
      var cipher = new AES256Cipher(key);
      return cipher.decryptBlock(userEncryption, false, new Uint8Array(16));
    }

  }

  return PDF20;
}();

exports.PDF20 = PDF20;

class CipherTransform {
  constructor(stringCipherConstructor, streamCipherConstructor) {
    this.StringCipherConstructor = stringCipherConstructor;
    this.StreamCipherConstructor = streamCipherConstructor;
  }

  createStream(stream, length) {
    var cipher = new this.StreamCipherConstructor();
    return new _stream.DecryptStream(stream, length, function cipherTransformDecryptStream(data, finalize) {
      return cipher.decryptBlock(data, finalize);
    });
  }

  decryptString(s) {
    var cipher = new this.StringCipherConstructor();
    var data = (0, _util.stringToBytes)(s);
    data = cipher.decryptBlock(data, true);
    return (0, _util.bytesToString)(data);
  }

  encryptString(s) {
    const cipher = new this.StringCipherConstructor();

    if (cipher instanceof AESBaseCipher) {
      const strLen = s.length;
      const pad = 16 - strLen % 16;

      if (pad !== 16) {
        s = s.padEnd(16 * Math.ceil(strLen / 16), String.fromCharCode(pad));
      }

      const iv = new Uint8Array(16);

      if (typeof crypto !== "undefined") {
        crypto.getRandomValues(iv);
      } else {
        for (let i = 0; i < 16; i++) {
          iv[i] = Math.floor(256 * Math.random());
        }
      }

      let data = (0, _util.stringToBytes)(s);
      data = cipher.encrypt(data, iv);
      const buf = new Uint8Array(16 + data.length);
      buf.set(iv);
      buf.set(data, 16);
      return (0, _util.bytesToString)(buf);
    }

    let data = (0, _util.stringToBytes)(s);
    data = cipher.encrypt(data);
    return (0, _util.bytesToString)(data);
  }

}

var CipherTransformFactory = function CipherTransformFactoryClosure() {
  var defaultPasswordBytes = new Uint8Array([0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);

  function createEncryptionKey20(revision, password, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms) {
    if (password) {
      var passwordLength = Math.min(127, password.length);
      password = password.subarray(0, passwordLength);
    } else {
      password = [];
    }

    var pdfAlgorithm;

    if (revision === 6) {
      pdfAlgorithm = new PDF20();
    } else {
      pdfAlgorithm = new PDF17();
    }

    if (pdfAlgorithm.checkUserPassword(password, userValidationSalt, userPassword)) {
      return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);
    } else if (password.length && pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt, uBytes, ownerPassword)) {
      return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes, ownerEncryption);
    }

    return null;
  }

  function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata) {
    var hashDataSize = 40 + ownerPassword.length + fileId.length;
    var hashData = new Uint8Array(hashDataSize),
        i = 0,
        j,
        n;

    if (password) {
      n = Math.min(32, password.length);

      for (; i < n; ++i) {
        hashData[i] = password[i];
      }
    }

    j = 0;

    while (i < 32) {
      hashData[i++] = defaultPasswordBytes[j++];
    }

    for (j = 0, n = ownerPassword.length; j < n; ++j) {
      hashData[i++] = ownerPassword[j];
    }

    hashData[i++] = flags & 0xff;
    hashData[i++] = flags >> 8 & 0xff;
    hashData[i++] = flags >> 16 & 0xff;
    hashData[i++] = flags >>> 24 & 0xff;

    for (j = 0, n = fileId.length; j < n; ++j) {
      hashData[i++] = fileId[j];
    }

    if (revision >= 4 && !encryptMetadata) {
      hashData[i++] = 0xff;
      hashData[i++] = 0xff;
      hashData[i++] = 0xff;
      hashData[i++] = 0xff;
    }

    var hash = calculateMD5(hashData, 0, i);
    var keyLengthInBytes = keyLength >> 3;

    if (revision >= 3) {
      for (j = 0; j < 50; ++j) {
        hash = calculateMD5(hash, 0, keyLengthInBytes);
      }
    }

    var encryptionKey = hash.subarray(0, keyLengthInBytes);
    var cipher, checkData;

    if (revision >= 3) {
      for (i = 0; i < 32; ++i) {
        hashData[i] = defaultPasswordBytes[i];
      }

      for (j = 0, n = fileId.length; j < n; ++j) {
        hashData[i++] = fileId[j];
      }

      cipher = new ARCFourCipher(encryptionKey);
      checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
      n = encryptionKey.length;
      var derivedKey = new Uint8Array(n),
          k;

      for (j = 1; j <= 19; ++j) {
        for (k = 0; k < n; ++k) {
          derivedKey[k] = encryptionKey[k] ^ j;
        }

        cipher = new ARCFourCipher(derivedKey);
        checkData = cipher.encryptBlock(checkData);
      }

      for (j = 0, n = checkData.length; j < n; ++j) {
        if (userPassword[j] !== checkData[j]) {
          return null;
        }
      }
    } else {
      cipher = new ARCFourCipher(encryptionKey);
      checkData = cipher.encryptBlock(defaultPasswordBytes);

      for (j = 0, n = checkData.length; j < n; ++j) {
        if (userPassword[j] !== checkData[j]) {
          return null;
        }
      }
    }

    return encryptionKey;
  }

  function decodeUserPassword(password, ownerPassword, revision, keyLength) {
    var hashData = new Uint8Array(32),
        i = 0,
        j,
        n;
    n = Math.min(32, password.length);

    for (; i < n; ++i) {
      hashData[i] = password[i];
    }

    j = 0;

    while (i < 32) {
      hashData[i++] = defaultPasswordBytes[j++];
    }

    var hash = calculateMD5(hashData, 0, i);
    var keyLengthInBytes = keyLength >> 3;

    if (revision >= 3) {
      for (j = 0; j < 50; ++j) {
        hash = calculateMD5(hash, 0, hash.length);
      }
    }

    var cipher, userPassword;

    if (revision >= 3) {
      userPassword = ownerPassword;
      var derivedKey = new Uint8Array(keyLengthInBytes),
          k;

      for (j = 19; j >= 0; j--) {
        for (k = 0; k < keyLengthInBytes; ++k) {
          derivedKey[k] = hash[k] ^ j;
        }

        cipher = new ARCFourCipher(derivedKey);
        userPassword = cipher.encryptBlock(userPassword);
      }
    } else {
      cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
      userPassword = cipher.encryptBlock(ownerPassword);
    }

    return userPassword;
  }

  var identityName = _primitives.Name.get("Identity");

  function buildObjectKey(num, gen, encryptionKey, isAes = false) {
    var key = new Uint8Array(encryptionKey.length + 9),
        i,
        n;

    for (i = 0, n = encryptionKey.length; i < n; ++i) {
      key[i] = encryptionKey[i];
    }

    key[i++] = num & 0xff;
    key[i++] = num >> 8 & 0xff;
    key[i++] = num >> 16 & 0xff;
    key[i++] = gen & 0xff;
    key[i++] = gen >> 8 & 0xff;

    if (isAes) {
      key[i++] = 0x73;
      key[i++] = 0x41;
      key[i++] = 0x6c;
      key[i++] = 0x54;
    }

    var hash = calculateMD5(key, 0, i);
    return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
  }

  function buildCipherConstructor(cf, name, num, gen, key) {
    if (!(0, _primitives.isName)(name)) {
      throw new _util.FormatError("Invalid crypt filter name.");
    }

    var cryptFilter = cf.get(name.name);
    var cfm;

    if (cryptFilter !== null && cryptFilter !== undefined) {
      cfm = cryptFilter.get("CFM");
    }

    if (!cfm || cfm.name === "None") {
      return function cipherTransformFactoryBuildCipherConstructorNone() {
        return new NullCipher();
      };
    }

    if (cfm.name === "V2") {
      return function cipherTransformFactoryBuildCipherConstructorV2() {
        return new ARCFourCipher(buildObjectKey(num, gen, key, false));
      };
    }

    if (cfm.name === "AESV2") {
      return function cipherTransformFactoryBuildCipherConstructorAESV2() {
        return new AES128Cipher(buildObjectKey(num, gen, key, true));
      };
    }

    if (cfm.name === "AESV3") {
      return function cipherTransformFactoryBuildCipherConstructorAESV3() {
        return new AES256Cipher(key);
      };
    }

    throw new _util.FormatError("Unknown crypto method");
  }

  class CipherTransformFactory {
    constructor(dict, fileId, password) {
      var filter = dict.get("Filter");

      if (!(0, _primitives.isName)(filter, "Standard")) {
        throw new _util.FormatError("unknown encryption method");
      }

      this.dict = dict;
      var algorithm = dict.get("V");

      if (!Number.isInteger(algorithm) || algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5) {
        throw new _util.FormatError("unsupported encryption algorithm");
      }

      this.algorithm = algorithm;
      var keyLength = dict.get("Length");

      if (!keyLength) {
        if (algorithm <= 3) {
          keyLength = 40;
        } else {
          var cfDict = dict.get("CF");
          var streamCryptoName = dict.get("StmF");

          if ((0, _primitives.isDict)(cfDict) && (0, _primitives.isName)(streamCryptoName)) {
            cfDict.suppressEncryption = true;
            var handlerDict = cfDict.get(streamCryptoName.name);
            keyLength = handlerDict && handlerDict.get("Length") || 128;

            if (keyLength < 40) {
              keyLength <<= 3;
            }
          }
        }
      }

      if (!Number.isInteger(keyLength) || keyLength < 40 || keyLength % 8 !== 0) {
        throw new _util.FormatError("invalid key length");
      }

      var ownerPassword = (0, _util.stringToBytes)(dict.get("O")).subarray(0, 32);
      var userPassword = (0, _util.stringToBytes)(dict.get("U")).subarray(0, 32);
      var flags = dict.get("P");
      var revision = dict.get("R");
      var encryptMetadata = (algorithm === 4 || algorithm === 5) && dict.get("EncryptMetadata") !== false;
      this.encryptMetadata = encryptMetadata;
      var fileIdBytes = (0, _util.stringToBytes)(fileId);
      var passwordBytes;

      if (password) {
        if (revision === 6) {
          try {
            password = (0, _util.utf8StringToString)(password);
          } catch (ex) {
            (0, _util.warn)("CipherTransformFactory: " + "Unable to convert UTF8 encoded password.");
          }
        }

        passwordBytes = (0, _util.stringToBytes)(password);
      }

      var encryptionKey;

      if (algorithm !== 5) {
        encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata);
      } else {
        var ownerValidationSalt = (0, _util.stringToBytes)(dict.get("O")).subarray(32, 40);
        var ownerKeySalt = (0, _util.stringToBytes)(dict.get("O")).subarray(40, 48);
        var uBytes = (0, _util.stringToBytes)(dict.get("U")).subarray(0, 48);
        var userValidationSalt = (0, _util.stringToBytes)(dict.get("U")).subarray(32, 40);
        var userKeySalt = (0, _util.stringToBytes)(dict.get("U")).subarray(40, 48);
        var ownerEncryption = (0, _util.stringToBytes)(dict.get("OE"));
        var userEncryption = (0, _util.stringToBytes)(dict.get("UE"));
        var perms = (0, _util.stringToBytes)(dict.get("Perms"));
        encryptionKey = createEncryptionKey20(revision, passwordBytes, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms);
      }

      if (!encryptionKey && !password) {
        throw new _util.PasswordException("No password given", _util.PasswordResponses.NEED_PASSWORD);
      } else if (!encryptionKey && password) {
        var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword, revision, keyLength);
        encryptionKey = prepareKeyData(fileIdBytes, decodedPassword, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata);
      }

      if (!encryptionKey) {
        throw new _util.PasswordException("Incorrect Password", _util.PasswordResponses.INCORRECT_PASSWORD);
      }

      this.encryptionKey = encryptionKey;

      if (algorithm >= 4) {
        var cf = dict.get("CF");

        if ((0, _primitives.isDict)(cf)) {
          cf.suppressEncryption = true;
        }

        this.cf = cf;
        this.stmf = dict.get("StmF") || identityName;
        this.strf = dict.get("StrF") || identityName;
        this.eff = dict.get("EFF") || this.stmf;
      }
    }

    createCipherTransform(num, gen) {
      if (this.algorithm === 4 || this.algorithm === 5) {
        return new CipherTransform(buildCipherConstructor(this.cf, this.stmf, num, gen, this.encryptionKey), buildCipherConstructor(this.cf, this.strf, num, gen, this.encryptionKey));
      }

      var key = buildObjectKey(num, gen, this.encryptionKey, false);

      var cipherConstructor = function buildCipherCipherConstructor() {
        return new ARCFourCipher(key);
      };

      return new CipherTransform(cipherConstructor, cipherConstructor);
    }

  }

  return CipherTransformFactory;
}();

exports.CipherTransformFactory = CipherTransformFactory;